package momo.multitree.simulation;

import java.io.FileReader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import momo.multitree.algo.EdmundAlgo;
import momo.multitree.algo.KrzyAlgo;
import momo.multitree.algo.LatencyShortestPath;
import momo.multitree.structure.Edge;
import momo.multitree.structure.Graph;
import momo.multitree.structure.Tree;
import momo.multitree.util.EdgeQuickSort;

public class SimulatedDifference
{
	private Log log = LogFactory.getLog(SimulatedDifference.class);
	
//	private String[] filenames = {"9_node_symmetric_dataset_48.txt"};
	
	private String[] filenames = {
			"5_node_symmetric_dataset_52.txt"
//			"5_node_symmetric_dataset_55.txt",
//			"5_node_symmetric_dataset_55.txt",
//			"5_node_symmetric_dataset_100.txt",
//			"6_node_symmetric_dataset_16.txt",
//			"6_node_symmetric_dataset_64.txt",
//			"6_node_symmetric_dataset_69.txt",
//			"6_node_symmetric_dataset_100.txt",
//			"7_node_symmetric_dataset_4.txt",
//			"7_node_symmetric_dataset_40.txt",
//			"7_node_symmetric_dataset_47.txt",
//			"7_node_symmetric_dataset_85.txt",
//			"8_node_symmetric_dataset_25.txt",
//			"8_node_symmetric_dataset_39.txt",
//			"8_node_symmetric_dataset_76.txt",
//			"8_node_symmetric_dataset_79.txt",
//			"8_node_symmetric_dataset_85.txt"
			};
	
	public SimulatedDifference()
	{
	}
	
	public void runEdgeDiff()
	{
		for(String filename: filenames)
		{
			try
			{
				Graph g = new Graph(new FileReader("dataset/"+filename));
				String visualFilename = filename.substring(0, filename.length()-4);
				
				SimulationWorker worker = new SimulationWorker(g);
				worker.runSimulation();
				Tree bestMCTree = worker.getBestTree();
//				bestMCTree.outputVisual(visualFilename+"_MC");
				
				int maxIteration = 100;
				int maxTrial = 100;
				double temperature = 1d;
				double factor = 0.95d;
				SimulatedAnnealing sim = new SimulatedAnnealing(g, maxIteration, maxTrial, temperature, factor);
				Tree bestSATree = sim.optimizeTree();
//				bestSATree.outputVisual(visualFilename+"_SA");
				
				Edge[] edgesMC = bestMCTree.getEdges().toArray(new Edge[0]);
				Edge[] edgesSA = bestSATree.getEdges().toArray(new Edge[0]);
				EdgeQuickSort.quickSort(edgesMC);
				EdgeQuickSort.quickSort(edgesSA);
				
				StringBuffer buffer = new StringBuffer();
				buffer.append("Root: "+bestMCTree.getRoot().getId());
				for(Edge e: edgesMC)
					buffer.append("|"+e.getId());
				
				buffer.append(", ");
				buffer.append("Root: "+bestSATree.getRoot().getId());
				for(Edge e: edgesSA)
					buffer.append("|"+e.getId());
				
				
				log.info(filename+", " + buffer.toString());
				
			}catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	public void runDistDiff()
	{
		log.debug("Start of Dist Diff test");
		for(String filename: filenames)
		{
			try
			{
				Graph g = new Graph(new FileReader("dataset/"+filename));
				
				LatencyShortestPath latTest = new LatencyShortestPath();
				Tree bestLatTree = latTest.optimumTree(g);
				
				KrzyAlgo costTest = new KrzyAlgo(g);
				Tree bestCostTree = costTest.optimumTree();
				
				EdmundAlgo stabTest = new EdmundAlgo(g);
				Tree bestStabTree = stabTest.optimumTree();
				
				double bestLat = bestLatTree.compWeightedLatency();
				double worstLat = bestCostTree.compWeightedLatency() > bestStabTree.compWeightedLatency() ? bestCostTree.compWeightedLatency() :  bestStabTree.compWeightedLatency();
				
				double bestCost = bestCostTree.compCost(false);
				double worstCost = bestLatTree.compCost(false) > bestStabTree.compCost(false) ? bestLatTree.compCost(false) : bestStabTree.compCost(false);  
				
				double bestStab = bestStabTree.compStability();
				double worstStab = bestLatTree.compStability() > bestCostTree.compStability() ? bestLatTree.compStability() : bestCostTree.compStability();
				
				SimulationWorker worker = new SimulationWorker(g);
				worker.runSimulation();
				Tree bestMCTree = worker.getBestTree();
				
				int maxIteration = 100;
				int maxTrial = 105;
				double temperature = 1d;
				double factor = 0.95d;
				SimulatedAnnealing sim = new SimulatedAnnealing(g, maxIteration, maxTrial, temperature, factor);
				Tree bestSATree = sim.optimizeTree();
				
				double distMC = dist(bestMCTree, bestLat, worstLat, bestCost, worstCost, bestStab, worstStab);
				double distSA = dist(bestSATree, bestLat, worstLat, bestCost, worstCost, bestStab, worstStab);
				
				double diff = distSA - distMC;
				double errorPercentage = diff / distMC;
				
				log.debug(filename + ", " + diff + ", " + errorPercentage);
				
			}catch(Exception e)
			{
				e.printStackTrace();
			}
		}
	}
	
	private double dist(Tree t, double bestLat, double worstLat, double bestCost, double worstCost, double bestStab, double worstStab)
	{
		double latT, costT, stabT;
		double lat = t.compWeightedLatency();
		double cost = t.compCost(false);
		double stab = t.compStability();
		
		if ( ( worstLat - bestLat ) == 0 )
			latT = 0;
		else
			latT = ( lat - bestLat ) / ( worstLat - bestLat );
//		if ( Double.isNaN(latT) || Double.isInfinite(latT) ) latT = 0;
		
		if ( ( worstCost - bestCost ) == 0 )
			costT = 0;
		else
			costT = ( cost - bestCost ) / ( worstCost - bestCost );
//		if ( Double.isNaN(costT) || Double.isInfinite(costT) ) costT = 0;
		
		if (  ( worstStab - bestStab ) == 0 )
			stabT = 0;
		else
			stabT = ( stab - bestStab ) / ( worstStab - bestStab );
//		if ( Double.isNaN(stabT) || Double.isInfinite(stabT) ) stabT = 0;

		double dist = Math.sqrt( Math.pow(latT, 2) + Math.pow(costT, 2) + Math.pow(stabT, 2) );
		return dist;
	}
	
	public static void main(String args[])
	{
		SimulatedDifference app = new SimulatedDifference();
		app.runEdgeDiff();
//		app.runDistDiff();
	}
}//end of class SimulatedDifference
